package sdk

import (
	"errors"
	"fmt"
	"github.com/hyperledger/fabric-sdk-go/pkg/client/channel"
	"github.com/hyperledger/fabric-sdk-go/pkg/client/ledger"
	mspclient "github.com/hyperledger/fabric-sdk-go/pkg/client/msp"
	"github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt"
	contextAPI "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/context"
	"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
	"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
	"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk"
)

/*
	fabric sdk管理
 */
type FabricSetup struct {
	ConfigFile      string
	OrdererID       string
	ChannelID       string
	AdminName       string
	OrgName         string
	UserName        string
	sdk             *fabsdk.FabricSDK
}

/*
	初始化 sdk 加载配置
 */
func (setup *FabricSetup) Initialize() error {
	sdk, err := fabsdk.New(config.FromFile(setup.ConfigFile))
	if err != nil {
		return errors.New("SDK 创建失败:" + err.Error())
	}
	setup.sdk = sdk
	fmt.Println("SDK 创建成功")
	return nil
}

func (setup *FabricSetup) CloseSDK() {
	setup.sdk.Close()
}

/*
	获取指定通道
 */
func (m *FabricSetup) GetChannel(channelId, orgAdmin, orgName string) (*channel.Client, error) {
	context := m.sdk.ChannelContext(channelId, fabsdk.WithUser(orgAdmin), fabsdk.WithOrg(orgName))
	client, err := channel.New(context)
	if err != nil {
		return nil, err
	}
	return client, nil
}

/*
	获取管理员客户端
*/
func (m *FabricSetup) GetAdminCli(orgAdmin, orgName string) (*resmgmt.Client, error) {
	context := m.sdk.Context(fabsdk.WithUser(orgAdmin), fabsdk.WithOrg(orgName))
	cli, err := resmgmt.New(context)
	if err != nil {
		return nil, err
	}
	return cli, nil
}

/*
	获取MSP客户端
 */
func (m *FabricSetup) GetMspCli(orgName string) (*mspclient.Client, error) {
	cli, err := mspclient.New(m.sdk.Context(), mspclient.WithOrg(orgName))
	if err != nil {
		return nil, err
	}
	return cli, nil
}

/*
	https://www.cnblogs.com/apolov-fabric/p/9719318.html
	底层分类帐的查询
 */
func (m *FabricSetup) GetLedger(channelId, userName, orgName string) (*ledger.Client, error) {
	channelContext := m.sdk.ChannelContext(channelId, fabsdk.WithUser(userName), fabsdk.WithOrg(orgName))
	cli, err := ledger.New(channelContext)
	if err != nil {
		return nil, err
	}
	return cli, nil
}

/*
	获取peer节点对象
 */
func (m *FabricSetup) GetPeer(orgName string, i int) (*fab.Peer, error) {
	var f contextAPI.ClientProvider
	ctx, err := f()
	if err != nil {
		return nil, err
	}
	peers, ok := ctx.EndpointConfig().PeersConfig(orgName)
	if !ok {
		return nil, errors.New("get peers error ")
	}

	peer, err := ctx.InfraProvider().CreatePeerFromConfig(&fab.NetworkPeer{PeerConfig: peers[i]})
	if err != nil {
		return nil, err
	}
	return &peer, nil
}
